﻿using Infrastructure.Extensions;
using Infrastructure.Helper;
using Infrastructure.Model;
using Microsoft.AspNetCore.Http;
using Minio;
using Minio.DataModel.Args;
using Minio.Exceptions;
using Newtonsoft.Json;

namespace Infrastructure.Centers
{
    public class FileCenter : IFileCenter
    {
        private readonly MinioClient minioClient;

        private readonly FileCenterOption optFileCenter;

        private readonly IHttpContextAccessor httpContextAccessor;

        public FileCenter(MinioClient minioClient, FileCenterOption optFileCenter, IHttpContextAccessor httpContextAccessor)
        {
            this.optFileCenter = optFileCenter;
            this.minioClient = minioClient;
            this.httpContextAccessor = httpContextAccessor;
            Task.Run(() => TaskCheckBucket());
        }

        public async Task TaskCheckBucket()
        {
            try
            {
                // 创建BucketExistsArgs实例
                var bucketExistsArgs = new BucketExistsArgs()
                    .WithBucket(optFileCenter.AppId.ToLower());

                if (!(await minioClient.BucketExistsAsync(bucketExistsArgs)))
                {
                    // 创建MakeBucketArgs实例，以便MakeBucketAsync调用
                    var makeBucketArgs = new MakeBucketArgs()
                        .WithBucket(optFileCenter.AppId.ToLower());

                    await minioClient.MakeBucketAsync(makeBucketArgs);
                    return;
                }

                throw new Exception("Use ServiceCenter Error : ");
            }
            catch (Exception ex)
            {
                // 无需重新分配exception变量，直接使用捕获的exception对象
                throw new Exception("Minio is failed to connected: " + ex.Message);
            }
        }
        public async Task<ApiResult> Remove(string fileGuid)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(fileGuid))
                {
                    return ApiResult.Error("FileId is needed");
                }

                ApiResult<FileInfos> apiResult = GetInfo(fileGuid);
                if (!apiResult.IsSuccess)
                {
                    return ApiResult.Error(apiResult.Msg);
                }

                try
                {
                    StatObjectArgs statObjectArgs = new StatObjectArgs().WithBucket(apiResult.Item.AppId.ToLower()).WithObject(fileGuid);
                    await minioClient.StatObjectAsync(statObjectArgs);
                }
                catch (Exception e3)
                {
                    return ApiResult.Error("MinioEx:[" + fileGuid + "] File not found, Ex：" + e3.Message);
                }

                RemoveObjectArgs rmArgs = new RemoveObjectArgs().WithBucket(apiResult.Item.AppId.ToLower()).WithObject(apiResult.Item.Guid);
                await minioClient.RemoveObjectAsync(rmArgs);
                string userId = httpContextAccessor?.HttpContext?.GetCurrentUserInfo()?.UserId ?? "-";
                string resDelete = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/api/File/Deleting", JsonConvert.SerializeObject(new FileDownloadReq
                {
                    FileGuid = fileGuid,
                    UserId = userId
                }));
                return ParseResult(resDelete);
            }
            catch (MinioException ex)
            {
                MinioException e2 = ex;
                return ApiResult.Error("Minio Api Failed Error: " + e2.Message);
            }
            catch (Exception ex2)
            {
                Exception e = ex2;
                return ApiResult.Error("Deleting Api Failed Error: " + e.Message);
            }
        }

        public ApiResult<FileInfos> GetInfo(string fileGuid)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(fileGuid))
                {
                    return ApiResult<FileInfos>.Error("FileId is needed");
                }

                string userId = httpContextAccessor?.HttpContext?.GetCurrentUserInfo()?.UserId ?? "-";
                string res = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/api/File/GetInfo", JsonConvert.SerializeObject(new FileDownloadReq
                {
                    FileGuid = fileGuid,
                    UserId = userId
                }));
                ApiResult apiResult = ParseResult(res);
                if (apiResult.IsSuccess)
                {
                    FileDownloadRes dtoFileDownloadRes = JsonConvert.DeserializeObject<FileDownloadRes>(apiResult.Data.ToString());
                    FileInfos item = new FileInfos
                    {
                        AppId = dtoFileDownloadRes.AppId,
                        Guid = fileGuid,
                        FileName = dtoFileDownloadRes.FileName,
                        FileSize = dtoFileDownloadRes.FileSize,
                        CreatedTime = dtoFileDownloadRes.CreatedAt,
                        CreatedBy = dtoFileDownloadRes.CreatedBy
                    };
                    return ApiResult<FileInfos>.Success(item);
                }

                return ApiResult<FileInfos>.Error(apiResult.Msg);
            }
            catch (Exception ex)
            {
                return ApiResult<FileInfos>.Error("GetInfo Api Error: " + ex.Message);
            }
        }

        public async Task<ApiResult<FileInfos>> Download(string fileGuid)
        {
            try
            {
                string userId = httpContextAccessor?.HttpContext?.GetCurrentUserInfo()?.UserId ?? "-";
                HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/api/File/Downloading", JsonConvert.SerializeObject(new FileDownloadReq
                {
                    FileGuid = fileGuid,
                    UserId = userId
                }));
                if (string.IsNullOrWhiteSpace(fileGuid))
                {
                    return ApiResult<FileInfos>.Error("FileId is needed");
                }

                ApiResult<FileInfos> apiResult = GetInfo(fileGuid);
                if (!apiResult.IsSuccess)
                {
                    return ApiResult<FileInfos>.Error(apiResult.Msg);
                }

                try
                {
                    StatObjectArgs statObjectArgs = new StatObjectArgs().WithBucket(apiResult.Item.AppId.ToLower()).WithObject(fileGuid);
                    await minioClient.StatObjectAsync(statObjectArgs);
                }
                catch (Exception e3)
                {
                    return ApiResult<FileInfos>.Error("MinioEx:[" + fileGuid + "] File not found, Ex：" + e3.Message);
                }

                MemoryStream fileStream = new MemoryStream();
                GetObjectArgs getObjectArgs = new GetObjectArgs().WithBucket(apiResult.Item.AppId.ToLower()).WithObject(fileGuid).WithCallbackStream(delegate (Stream stream)
                {
                    stream.CopyTo(fileStream);
                });
                await minioClient.GetObjectAsync(getObjectArgs);
                fileStream.Position = 0L;
                apiResult.Item.FileContent = fileStream.ToArray();
                fileStream.Flush();
                return ApiResult<FileInfos>.Success(apiResult.Item);
            }
            catch (MinioException ex)
            {
                MinioException e2 = ex;
                return ApiResult<FileInfos>.Error("MinioEx Downloading Error: " + e2.Message);
            }
            catch (Exception ex2)
            {
                Exception e = ex2;
                return ApiResult<FileInfos>.Error("Download Api Error: " + e.Message);
            }
        }

        public async Task<ApiResult> Upload(IFormFile formFile)
        {
            if (formFile == null || string.IsNullOrWhiteSpace(formFile.FileName))
            {
                return ApiResult<FileInfos>.Error("formFile is needed");
            }

            if (formFile.Length == 0)
            {
                return ApiResult<FileInfos>.Error("File is Empty Content");
            }

            return await Upload(formFile.FileName, formFile.OpenReadStream());
        }

        public async Task<ApiResult> Upload(string fileName, Stream fileContent)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            {
                return ApiResult<FileInfos>.Error("FileName is needed");
            }

            if (fileContent.Length == 0)
            {
                return ApiResult<FileInfos>.Error("File is Empty Content");
            }

            string guid = Guid.NewGuid().ToString();
            try
            {
                try
                {
                    PutObjectArgs putObjectArgs = new PutObjectArgs().WithBucket(optFileCenter.AppId.ToLower()).WithObject(guid).WithObjectSize(fileContent.Length)
                        .WithStreamData(fileContent)
                        .WithContentType("application/octet-stream");
                    await minioClient.PutObjectAsync(putObjectArgs);
                }
                catch (MinioException ex)
                {
                    MinioException e2 = ex;
                    return ApiResult.Error("Minio Ex:" + e2.Message);
                }

                string userId = httpContextAccessor?.HttpContext?.GetCurrentUserInfo()?.UserId ?? "-";
                string res = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/api/File/Uploaded", JsonConvert.SerializeObject(new FileUploadReq
                {
                    AppId = optFileCenter.AppId,
                    FileName = fileName,
                    FileGuid = guid,
                    FileSize = fileContent.Length,
                    CreatedBy = userId
                }));
                ApiResult apiRes = ParseResult(res);
                if (!apiRes.IsSuccess)
                {
                    RemoveObjectArgs rmArgs = new RemoveObjectArgs().WithBucket(optFileCenter.AppId.ToLower()).WithObject(guid);
                    await minioClient.RemoveObjectAsync(rmArgs);
                    return ApiResult.Error("Upload Api Ex:" + apiRes.Msg);
                }

                return ApiResult.Success(guid);
            }
            catch (Exception e)
            {
                return ApiResult.Error("File Center Ex:" + e.Message);
            }
        }

        public ApiResult IsExists(string fileGuid)
        {
            if (string.IsNullOrWhiteSpace(fileGuid))
            {
                return ApiResult<FileInfos>.Error("FileId is needed");
            }

            return GetInfo(fileGuid);
        }

        public ApiResult<FileInfos[]> GetInfos(string[] fileGuids)
        {
            try
            {
                if (fileGuids.Length == 0)
                {
                    return ApiResult<FileInfos[]>.Error("FileIds is needed");
                }

                List<FileDownloadReq> list = new List<FileDownloadReq>();
                string userId = httpContextAccessor?.HttpContext?.GetCurrentUserInfo()?.UserId ?? "-";
                foreach (string text in fileGuids)
                {
                    if (string.IsNullOrWhiteSpace(text))
                    {
                        return ApiResult<FileInfos[]>.Error("FileIds contains empty element");
                    }

                    list.Add(new FileDownloadReq
                    {
                        FileGuid = text,
                        UserId = userId
                    });
                }

                string res = HttpHelper.HttpPost(optFileCenter.FileCenterUrl + "/api/File/GetInfos", JsonConvert.SerializeObject(list.ToArray()));
                ApiResult apiResult = ParseResult(res);
                if (apiResult.IsSuccess)
                {
                    FileDownloadRes[] array = JsonConvert.DeserializeObject<FileDownloadRes[]>(apiResult.Data.ToString());
                    List<FileInfos> list2 = new List<FileInfos>();
                    FileDownloadRes[] array2 = array;
                    foreach (FileDownloadRes dtoFileDownloadRes in array2)
                    {
                        list2.Add(new FileInfos
                        {
                            AppId = dtoFileDownloadRes.AppId,
                            Guid = dtoFileDownloadRes.Guid,
                            FileName = dtoFileDownloadRes.FileName,
                            FileSize = dtoFileDownloadRes.FileSize,
                            CreatedTime = dtoFileDownloadRes.CreatedAt,
                            CreatedBy = dtoFileDownloadRes.CreatedBy
                        });
                    }

                    return ApiResult<FileInfos[]>.Success(list2.ToArray());
                }

                return ApiResult<FileInfos[]>.Error(apiResult.Msg);
            }
            catch (Exception ex)
            {
                return ApiResult<FileInfos[]>.Error("GetInfo Api Error: " + ex.Message);
            }
        }

        private ApiResult ParseResult(string res)
        {
            if (!string.IsNullOrWhiteSpace(res))
            {
                try
                {
                    return JsonConvert.DeserializeObject<ApiResult>(res);
                }
                catch (Exception ex)
                {
                    return ApiResult.Error("Api Failed : " + ex.Message);
                }
            }

            return ApiResult.Error("Api Failed, Empty Response");
        }
    }
}
